package service

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"share/msg"
	"util/log"
)

type typehelper interface {
	UserVal() []interface{}
	UserType(name string) [][]string
}

func parseMsg(index int, serial int, data []byte, size int) {
	b := data[:size]
	buf := bytes.NewBuffer(b)
	dec := gob.NewDecoder(buf)
	dbmsg := msg.DBMsg{}
	err := dec.Decode(&dbmsg)
	if err != nil {
		log.TraceInfo("dbservice", "msg unpack failed")
		return
	}

	switch dbmsg.MsgId {
	case msg.DBMSG_SAVE_OBJECT:
		saveObject(index, serial, dec)
	case msg.DBMSG_SAVE_CHILD_OBJECT:
		saveChildObject(index, serial, dec)
	}
}

func getTypeStr(name string, val interface{}) []string {

	if helper, ok := val.(typehelper); ok {
		t := helper.UserType(name)
		ta := make([]string, 0, 16)
		for _, v := range t {
			ta = append(ta, v[0])
		}
		return ta
	}

	return []string{"p_" + name}
}

func getValStr(val interface{}) []interface{} {
	if helper, ok := val.(typehelper); ok {
		return helper.UserVal()
	}

	return []interface{}{val}
}

func insertIntoDb(tbl_name string, fields []msg.PropData) (string, []interface{}) {
	sql := make([]byte, 0, 2024)
	sql = append(sql, []byte("INSERT INTO `"+tbl_name+"` (`id`")...)
	val := make([]byte, 0, 1024)
	val = append(val, []byte("?")...)
	args := make([]interface{}, 0, 56)
	args = append(args, 0)

	for _, f := range fields {

		types := getTypeStr(f.Name, f.Val)
		arg := getValStr(f.Val)
		if len(types) != len(arg) {
			fmt.Println(types)
			fmt.Println(arg)
			panic("type error")
		}
		for _, t := range types {
			sql = append(sql, []byte(","+t)...)
			val = append(val, []byte(",?")...)
		}

		args = append(args, arg...)

	}
	sql = append(sql, []byte(") VALUES(")...)
	sql = append(sql, val...)
	sql = append(sql, []byte(")")...)
	return string(sql), args
}

func saveObject(index int, serial int, dec *gob.Decoder) {
	saveobj := msg.SaveObject{}
	err := dec.Decode(&saveobj)
	if err != nil {
		log.TraceInfo("dbservice", "save object msg error")
		return
	}

	data := saveobj.Data
	if data.Dbid == 0 {
		for _, o := range data.Data {
			insertIntoDb("tbl_"+o.Type, o.Props)
		}

	}
}

func saveChildObject(index int, serial int, dec *gob.Decoder) {
	saveobj := msg.SaveChildObject{}
	err := dec.Decode(&saveobj)
	if err != nil {
		log.TraceInfo("dbservice", "save child object msg error")
		return
	}

	fmt.Println(saveobj)
}
